use strict;
use warnings;

use Tk;
use Tk::WorldCanvas;
use Tk::LabEntry;

use lib '.';
use Physics::Simulation;

my $size         =   8;
my $paused       =   1;
my $mass         =   1;
my $k            =   500;
my $sim = Physics::Simulation->new();
$sim->constant_force_add('gravity', 0,-2000,0);
$sim->force_add('friction', 
	sub {
		my $particle = shift;
		return $particle->{vel} * -5;
	}
);
# $sim->binding_force_add('gravity', 
	# sub {
		# my ($P1, $P2) = (shift,shift);
		# my $v = $P2->{pos} - $P1->{pos};
		# return ($v->norm * (($P1->{mass} * $P2->{mass}) / $v->length()**2));
	# }
# );

use Data::Dumper;
my $mw           = MainWindow->new();
my $menu_bar     = $mw->Frame(-relief => 'groove', -borderwidth =>1
                             )->pack(-side=>'top', -fill => 'x');
my $display_area = $mw->Frame()->pack(-side=>'top',-fill=>'x');
my $worldcanvas  = $display_area->WorldCanvas(-width=>400,-height=>400);
							 
$menu_bar->Button(-text=>'Start', -command => sub { $paused = !$paused; })->pack(-side=>'left');
$menu_bar->LabEntry(-label=>'Mass'    , -textvariable=>\$mass)->pack(-side=>'left');

my $i = 1;
$worldcanvas->configure(-bandColor => 'purple');
my $spring_start = undef;
$worldcanvas->CanvasBind('<1>' =>
	sub {
		my ($x,$y) = $worldcanvas->eventLocation;
		my ($xv, $yv) = (0,0);
		# my ($xv, $yv) = (rand(20)-10,rand(20)-10);
		my $name = "node_" . rand(1000);
		my $t = $sim->particle_add( pos => [$x, $y, 0], vel => [$xv, $yv,0], mass=>$mass, name => $name);
		$worldcanvas->createOval( $x-$size,$y-$size,$x+$size,$y+$size, -fill=>'red', -tag=> ['node',$name]);
		$sim->spring_add( "spring_" . $t, $spring_start, $t, $k, 100);
		print "Inserting at $name ($x->$xv,$y->$yv)\n";
		#$worldcanvas->update();
		$worldcanvas->raise('node');
	}
);

$worldcanvas->CanvasBind('<3>' =>
	sub {
		my ($x,$y) = $worldcanvas->eventLocation;
		my ($xv, $yv) = (0,0);
		my $name = "node_" . rand(1000);
		$spring_start = $sim->particle_add( pos => [$x, $y, 0], mass => 10_000, fixed=>1, name=>$name);
		$worldcanvas->createOval( $x-$size,$y-$size,$x+$size,$y+$size, -fill=>'yellow', -tag=> ['node',$name]);
		print "Inserting at $name ($x->$xv,$y->$yv)\n";
		#$worldcanvas->update();
		$worldcanvas->raise('node');
	}
);


$worldcanvas->CanvasBind('<Up>' => sub {$worldcanvas->rubberBand(1);});
$worldcanvas->CanvasBind('<Down>' => sub {$worldcanvas->rubberBand(1);});
$worldcanvas->CanvasBind('<Left>' => sub {$worldcanvas->rubberBand(1);});
$worldcanvas->CanvasBind('<Right>' => sub {$worldcanvas->rubberBand(1);});
$worldcanvas->CanvasBind('<i>' => sub {$worldcanvas->zoom(1.25); $worldcanvas->rubberBand(1);});
$worldcanvas->CanvasBind('<o>' => sub {$worldcanvas->zoom(0.8);  $worldcanvas->rubberBand(1);});
$worldcanvas->pack();
$worldcanvas->CanvasFocus;
$worldcanvas->repeat(100, 
		sub {
			foreach my $spring (@{$sim->{springs}}) {
				my $p1 = $spring->{p1};
				my $p2 = $spring->{p2};
				my $spring_name = $spring->{name};
				if ($worldcanvas->find('withtag',$spring_name)) {
					$worldcanvas->coords($spring_name, $p1->{pos}->x, $p1->{pos}->y,
                                    				   $p2->{pos}->x, $p2->{pos}->y);
					#print "$spring_name ", $spring->{strech}, "\n";
				} else {
					$worldcanvas->createLine($p1->{pos}->x, $p1->{pos}->y,
                            		 		 $p2->{pos}->x, $p2->{pos}->y, -tag=>$spring_name);
			    }			
			}
		    $worldcanvas->raise('node');
			foreach my $p ( @{$sim->{p}} ) {
				$worldcanvas->coords($p->{name},  $p->{pos}->x - $size , $p->{pos}->y - $size, $p->{pos}->x + $size , $p->{pos}->y + $size );
			}	
		});
$worldcanvas->repeat(5, 
		sub {
		    unless ($paused) {
				$sim->iterate_step(0.0001) for (1..5);
			}
		});		

MainLoop;
